﻿using System;

namespace log_mgr {
	using System.Diagnostics;
	using Serilog;
	using Serilog.Events;
	using i_core;
	using System.Text;
	using common;
	using System.IO;
	using System.Net;

	public class serilog_log : i_log {
		public log_type type => log_type.serilog;

		public string user { get; set; }

		/// <summary>
		/// default info (0x1e)
		/// debug(0xff), info(0x1e), warn(0x1c), error(0x18), fatal(0x10), nolog(0x00)
		/// </summary>
		public log_level log_level { get; set; } = log_level.debug;

		public bool IsFatalEnabled => (((int)log_level >> 4) & 0x01) == 1;

		public bool IsErrorEnabled => (((int)log_level >> 3) & 0x01) == 1;

		public bool IsWarnEnabled => (((int)log_level >> 2) & 0x01) == 1;

		public bool IsInfoEnabled => (((int)log_level >> 1) & 0x01) == 1;

		public bool IsDebugEnabled => ((int)log_level & 0x01) == 1;

		private ILogger console_log, file_log;

		public serilog_log() { }

		public serilog_log(string user, bool islog) {
			this.user = user;

			const string outputTemplate = "[{Timestamp:HH:mm:ss.FFF} {Level}] {Message} {NewLine}{Exception}";
			var console_conf = new LoggerConfiguration()
				.MinimumLevel.Verbose()
				.Enrich.FromLogContext()
				.WriteTo.LiterateConsole(LogEventLevel.Verbose);
			console_log = console_conf.CreateLogger();

			var file_path = Directory.GetCurrentDirectory() + ($"/logs/{DateTime.Now:yyyyMMdd}.log");
			var file_conf = new LoggerConfiguration()
				.MinimumLevel.Verbose()
				.Enrich.FromLogContext()
				.WriteTo.File(file_path, shared: true, restrictedToMinimumLevel: LogEventLevel.Verbose,
					outputTemplate: outputTemplate, fileSizeLimitBytes: 10240000);
			file_log = file_conf.CreateLogger();
		}


		private message get_msg(string m, string cl) {
			return new message() { user = user, cl = cl, msg = m };
		}

		private message get_msg(Exception ex, string cl) {
			return new message() { user = user, cl = cl, msg = ex.Message };
		}


		#region method debug 

		public void Debug(object message) {

			var trace = new StackTrace();
			var frame = trace.GetFrame(1);
			var method = frame.GetMethod();
			var j_p = method.DeclaringType.FullName.IndexOf('+');
			var methor_name = method.DeclaringType.FullName.Substring(0, j_p <= 0 ? method.DeclaringType.FullName.Length : j_p);

			if (IsDebugEnabled)
				console_log.Debug($"[{user}] [{methor_name}] {message}");

			file_log.Debug($"[{user}] [{methor_name}] {message}");
		}

		public void Debug(object message, params object[] propertyValues) {

			var trace = new StackTrace();
			var frame = trace.GetFrame(1);
			var method = frame.GetMethod();
			var j_p = method.DeclaringType.FullName.IndexOf('+');
			var methor_name = method.DeclaringType.FullName.Substring(0, j_p <= 0 ? method.DeclaringType.FullName.Length : j_p);

			if (IsDebugEnabled)
				console_log.Debug($"[{user}] [{methor_name}] {message}", propertyValues);
			file_log.Debug($"[{user}] [{methor_name}] {message}", propertyValues);
		}

		public void Debug(object message, Exception exception) {
			var trace = new StackTrace();
			var frame = trace.GetFrame(1);
			var method = frame.GetMethod();
			var j_p = method.DeclaringType.FullName.IndexOf('+');
			var methor_name = method.DeclaringType.FullName.Substring(0, j_p <= 0 ? method.DeclaringType.FullName.Length : j_p);

			if (IsDebugEnabled)
				console_log.Debug(exception, $"[{user}] [{methor_name}] {message}");
			file_log.Debug(exception, $"[{user}] [{methor_name}] {message}");
		}

		public void DebugFormat(string format, params object[] args) {
			throw new NotImplementedException();
		}

		#endregion


		#region method Info 
		public void Info(object message, Exception exception) {
			var trace = new StackTrace();
			var frame = trace.GetFrame(1);
			var method = frame.GetMethod();
			var j_p = method.DeclaringType.FullName.IndexOf('+');
			var methor_name = method.DeclaringType.FullName.Substring(0, j_p <= 0 ? method.DeclaringType.FullName.Length : j_p);

			if (IsInfoEnabled)
				console_log.Information(exception, $"[{user}] [{methor_name}] {message}");
			file_log.Information(exception, $"[{user}] [{methor_name}] {message}");

		}

		public void Info(object message) {

			var trace = new StackTrace();
			var frame = trace.GetFrame(1);
			var method = frame.GetMethod();
			var j_p = method.DeclaringType.FullName.IndexOf('+');
			var methor_name = method.DeclaringType.FullName.Substring(0, j_p <= 0 ? method.DeclaringType.FullName.Length : j_p);

			if (IsInfoEnabled)
				console_log.Information($"[{user}] [{methor_name}] {message}");
			file_log.Information($"[{user}] [{methor_name}] {message}");
		}

		public void Info(object message, params object[] propertyValues) {
			var trace = new StackTrace();
			var frame = trace.GetFrame(1);
			var method = frame.GetMethod();
			var j_p = method.DeclaringType.FullName.IndexOf('+');
			var methor_name = method.DeclaringType.FullName.Substring(0, j_p <= 0 ? method.DeclaringType.FullName.Length : j_p);

			file_log.Information($"[{user}] [{methor_name}] {message}", propertyValues);
			if (IsInfoEnabled)
				console_log.Information($"[{user}] [{methor_name}] {message}", propertyValues);
		}

		public void InfoFormat(string format, params object[] args) {
			throw new NotImplementedException();
		}

		#endregion


		#region method Warn 
		public void Warn(object message) {

			var trace = new StackTrace();
			var frame = trace.GetFrame(1);
			var method = frame.GetMethod();
			var j_p = method.DeclaringType.FullName.IndexOf('+');
			var methor_name = method.DeclaringType.FullName.Substring(0, j_p <= 0 ? method.DeclaringType.FullName.Length : j_p);

			if (IsWarnEnabled)
				console_log.Warning($"[{user}] [{methor_name}] {message}");
			file_log.Warning($"[{user}] [{methor_name}] {message}");
		}

		public void Warn(object message, Exception exception) {
			var trace = new StackTrace();
			var frame = trace.GetFrame(1);
			var method = frame.GetMethod();
			var j_p = method.DeclaringType.FullName.IndexOf('+');
			var methor_name = method.DeclaringType.FullName.Substring(0, j_p <= 0 ? method.DeclaringType.FullName.Length : j_p);

			if (IsWarnEnabled)
				console_log.Warning(exception, $"[{user}] [{methor_name}] {message}");
			file_log.Warning(exception, $"[{user}] [{methor_name}] {message}");
		}

		public void Warn(object message, params object[] propertyValues) {
			var trace = new StackTrace();
			var frame = trace.GetFrame(1);
			var method = frame.GetMethod();
			var j_p = method.DeclaringType.FullName.IndexOf('+');
			var methor_name = method.DeclaringType.FullName.Substring(0, j_p <= 0 ? method.DeclaringType.FullName.Length : j_p);

			if (IsWarnEnabled)
				console_log.Warning($"[{user}] [{methor_name}] {message}", propertyValues);
			file_log.Warning($"[{user}] [{methor_name}] {message}", propertyValues);
		}


		#endregion


		#region method error 
		public void Error(object message) {
			var trace = new StackTrace();
			var frame = trace.GetFrame(1);
			var method = frame.GetMethod();
			var j_p = method.DeclaringType.FullName.IndexOf('+');
			var methor_name = method.DeclaringType.FullName.Substring(0, j_p <= 0 ? method.DeclaringType.FullName.Length : j_p);

			if (IsErrorEnabled)
				console_log.Error($"[{user}] [{methor_name}] {message}");
			file_log.Error($"[{user}] [{methor_name}] {message}");
		}

		public void Error(object message, params object[] propertyValues) {
			var trace = new StackTrace();
			var frame = trace.GetFrame(1);
			var method = frame.GetMethod();
			var j_p = method.DeclaringType.FullName.IndexOf('+');
			var methor_name = method.DeclaringType.FullName.Substring(0, j_p <= 0 ? method.DeclaringType.FullName.Length : j_p);

			if (IsErrorEnabled)
				console_log.Error($"[{user}] [{methor_name}] {message}", propertyValues);
			file_log.Error($"[{user}] [{methor_name}] {message}", propertyValues);
		}

		public void Error(object message, Exception exception) {
			var trace = new StackTrace();
			var frame = trace.GetFrame(1);
			var method = frame.GetMethod();
			var j_p = method.DeclaringType.FullName.IndexOf('+');
			var methor_name = method.DeclaringType.FullName.Substring(0, j_p <= 0 ? method.DeclaringType.FullName.Length : j_p);

			if (IsErrorEnabled)
				console_log.Error(exception, $"[{user}] [{methor_name}] {message}");
			file_log.Error(exception, $"[{user}] [{methor_name}] {message}");
		}

		public void ErrorFormat(string format, params object[] args) {
			throw new NotImplementedException();
		}

		#endregion


		#region method Fatal 
		public void Fatal(object message) {

			var trace = new StackTrace();
			var frame = trace.GetFrame(1);
			var method = frame.GetMethod();
			var j_p = method.DeclaringType.FullName.IndexOf('+');
			var methor_name = method.DeclaringType.FullName.Substring(0, j_p <= 0 ? method.DeclaringType.FullName.Length : j_p);

			if (IsFatalEnabled)
				console_log.Fatal($"[{user}] [{methor_name}] {message}");
			file_log.Fatal($"[{user}] [{methor_name}] {message}");
		}

		public void Fatal(object message, Exception exception) {
			var trace = new StackTrace();
			var frame = trace.GetFrame(1);
			var method = frame.GetMethod();
			var j_p = method.DeclaringType.FullName.IndexOf('+');
			var methor_name = method.DeclaringType.FullName.Substring(0, j_p <= 0 ? method.DeclaringType.FullName.Length : j_p);

			if (IsFatalEnabled)
				console_log.Fatal(exception, $"[{user}] [{methor_name}] {message}");
			file_log.Fatal(exception, $"[{user}] [{methor_name}] {message}");
		}

		public void Fatal(object message, params object[] propertyValues) {
			var trace = new StackTrace();
			var frame = trace.GetFrame(1);
			var method = frame.GetMethod();
			var j_p = method.DeclaringType.FullName.IndexOf('+');
			var methor_name = method.DeclaringType.FullName.Substring(0, j_p <= 0 ? method.DeclaringType.FullName.Length : j_p);

			if (IsFatalEnabled)
				console_log.Fatal($"[{user}] [{methor_name}] {message}", propertyValues);
			file_log.Fatal($"[{user}] [{methor_name}] {message}", propertyValues);
		}

		public void FatalFormat(string format, params object[] args) {
			throw new NotImplementedException();
		}


		#endregion
	}
}
